# -*- coding: UTF-8 -*-
'''
@Project ：pythonProject 
@File    ：testpyqt.py
@Author  ：小浩
@Date    ：2022/12/6 16:45 
'''
import sys
import time

from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap, QCursor, QIcon
from PyQt5.QtWidgets import QWidget, QLabel, QApplication, QPushButton, QLineEdit, QMainWindow

# region  官方教程第一个部分
# 制造一个按钮， 然后鼠标放在按钮上时会有提示
# import sys
# from PyQt5.QtWidgets import QApplication, QWidget, QToolTip, QPushButton
# from PyQt5.QtGui import QIcon, QFont
#
# class Example(QWidget):
#
#     def __init__(self):
#         super().__init__()
#         self.initUI()
#
#     def initUI(self):
#         QToolTip.setFont(QFont('宋体', 20))
#         self.setToolTip('This is a <b>QWidget</b> widget')
#         btn = QPushButton('Button 随便写点东西实验一下，看一下这个文本框能有多大', self)
#         btn.setToolTip('This is a <b>QPushButton</b> widget')
#         btn.resize(btn.sizeHint())
#         btn.move(50, 50)
#
#         self.setGeometry(300, 300, 300, 220)
#         self.setWindowTitle("Icon")
#         # self.setWindowIcon(QIcon('imgs/123.png'))
#         self.show()
#
# if __name__=='__main__':
#     app = QApplication(sys.argv)
#     ex = Example()
#     sys.exit(app.exec_())
    # print(sys.argv)
    # app = QApplication(sys.argv)
    # w = QWidget()
    # w.resize(300,300)
    # w.move(300,300)
    # w.setWindowTitle("第一个PyQt小应用")
    # w.show()
    # sys.exit(app.exec())
    # # while 1:
    # #     pass


# region
#endregion
#region  下面这个例子是演示如何通过程序关闭窗口

# 本例使用的是QPushButton组件类
# import sys
# from PyQt5.QtWidgets import QWidget, QPushButton, QApplication
# from PyQt5.QtCore import QCoreApplication
#
# class Example(QWidget):
#     def __init__(self):
#         super().__init__()
#         self.initUI()
#
#     def initUI(self):
#         qbtn = QPushButton('Quit', self)
#         qbtn.clicked().connect(QCoreApplication.instance().quit())
#         qbtn.clicked.connect(QCoreApplication.instance().quit())
#         qbtn.resize(qbtn.sizeHint())
#         qbtn.move(50, 50)
#
#         self.setGeometry(300, 300, 250, 150)
#         self.setWindowTitle('Quit button')
#         self.show()
#
# if __name__ == '__main__':
#     app  = QApplication(sys.argv)
#     ex =Example()
#     sys.exit(app.exec_())


# region 博客第一个教程部分
# import sys
# from PyQt5.QtWidgets import QWidget, QPushButton, QApplication, qApp, QLabel
# from PyQt5.QtCore import QCoreApplication
#
# app = QApplication(sys.argv)        # sys.argv 放在这里暂时没有什么用，但是当使用命令行启动这个脚本的时候，sys.argv中会有命令行的参数
# print(sys.argv)
# print(app.arguments())     #  得到的命令行参数
# print(qApp.arguments())    # 位于qApp模块中的一个全局变量   这三个变量的值都是一样的
#
# #创建一个窗口
# w = QWidget()
# w.resize(300, 300)    # 设置窗口尺寸
# w.move(800, 300)   # 移动窗口， 坐标原点为窗口左上角
# w.setWindowTitle("第一个基于pyqt5的桌面应用")
#
# # 设置标签
# label = QLabel(w)    # 以w窗口为父对象创建 标签对象
# label.setText("hello world")   # 设置标签的位置
# label.move(0, 75)    #  设置标签在窗口中的位置
#
# w.show()
#
# # 下面这一步很重要也很关键  是显示窗口的关键，
# #  进入程序的消息循环， 并通过exit函数确保 主循环安全结束， 相当于无限循环
# # 并在循环过程中检测  整个程序接收到的用户交互信息
# sys.exit(app.exec_())
# endregion


# region  第二个部分，本来是想教模板的，但是没教好
# from  PyQt5.Qt import *
#
# from PyQt5.QtCore import QObject
# from PyQt5.QtWidgets import QLabel
# from PyQt5.QtWidgets import QWidget, QApplication
#
#
# class Window(QWidget):
#
#     def __init__(self):
#         super(Window, self).__init__()
#         self.setWindowTitle("Hello")  # 设置标题
#         self.resize(300, 150)  # 设置窗口大小
#         self.move(300, 300)  # 移动窗口
#         self.setup_label()  # 调用创建控件的方法
#
#
#     def setup_label(self):  # 添加控件的操作
#         label = QLabel(self)
#         label.setText("Hello World")
#         label.move(150, 75)
#
#
# if __name__ == '__main__':
#     # 可以通过导包来运行窗口
#     import sys
#
#     app = QApplication(sys.argv)
#     # 创建窗口
#     w = Window()
#     # 显示窗口
#     w.show()
#     sys.exit(app.exec_())

#endregion

#region  第三个部分  教基本控件，  ，每类控件具有不同功能


# from PyQt5.Qt import *
# from PyQt5.QtCore import QObject
#
# obj = QObject()   # 这里教程里面还有点错了
# obj.setObjectName('notice obj对象的名称') # 设置Qt对象的名称
# print(obj.objectName())      # 获得Qt对象的名称
# obj.setProperty('notice_12', 'error')    # 设置对象的属性
# obj.setProperty('notice_12', 'warning')
# print(obj.property('notice_12'))   # 获得一个对象的属性值
# print(obj.dynamicPropertyNames())    # 获取一个对象中所有通过setProperty 设置的属性名称
#

# 上面一小段只是 简单的介绍，  下面说应用场景


# qss 样式表，相当于前端的 css 样式表，可以将其放入一个 `.qss` 的文件中，方便分离和读取，同时，所有符合条件的内容都会变成相应的样式

# from PyQt5.QtWidgets import QWidget, QLabel, qApp, QApplication
#
#
# class Window(QWidget):
#
#     def __init__(self):
#         super().__init__()
#         self.setWindowTitle("QObject")  # 设置标题
#         self.resize(500, 300)  # 设置窗口大小
#         self.move(500, 500)  # 移动窗口
#         self.setup_ui()  # 调用创建控件的方法
#
#     def setup_ui(self):  # 添加控件的操作
#         self.qObject_ui()
#
#     def qObject_ui(self):  # 所有类的基类
#         # 案例演示
#         label = QLabel(self)  # 创建标签
#         label.setText("Hello")  # 设置标签内容
#         label.setObjectName("notice")  # id 为 notice
#         label.setProperty("level", "error")  # 属性选择器
#         with open("resources\\QStyle.qss", "r") as f:
#             # qApp.setStyleSheet("font-size: 20px; color: blue;" )
#             #  更加方便且灵活的写法
#             label.setStyleSheet(f.read())   # 设置字体等样式
# ## qss 样式表，相当于前端的 css 样式表，可以将其放入一个 `.qss` 的文件中，方便分离和读取，同时，所有符合条件的内容都会变成相应的样式
#
#             """
#             文件内容为：
#             QLabel#notice[level='error'] {
#             font-size: 20px;
#             color: blue;
#             }
#             """
#
# if __name__ == '__main__':
#     # 可以通过导包来运行窗口
#     import sys
#
#     app = QApplication(sys.argv)
#     # 创建窗口
#     w = Window()
#     # 显示窗口
#     w.show()
#     sys.exit(app.exec_())

#endregion



#region 1.3 父子对象


# obj1 = QObject()
# obj2 = QObject()
# obj3 = QObject()

# obj2.setParent(obj1)  # 设置父子关系
# obj3.setObjectName("2")   # 设置 对象的id
# obj3.setParent(obj2)
# print(obj1, obj2.parent())     # 获取父类 ， 返回内容地址
# print(obj2, obj1.children())    # 获取所有直系对象
# print(obj1.findChild(QObject))  # 获取后代 ， 递归查找， 只返回一个
# print(obj1.findChild(QObject, "2")) # 获取id为2 的后代， 只返回一个
# print(obj1.findChildren(QObject))     #获取符合条件的所有后代

# 应用场景，  在控制过程中构建父子关系，  父控件删除， 那么子控件也会自动删除    内存管理机制

# 案例一
# obj1 = QObject()
# obj2 = QObject()
# obj1.setParent(obj2)
# #  监听 obj2 对象被释放
# obj2.destroyed.connect(lambda:print("obj2 , 被释放"))      # 这个connect 非常值得注意
# # 这个 connect 是一个信号接收函数， 一旦受到某个信号， 比如这里是obj2被删除，就会触发执行预设的操作
# print("删除父对象")
# del obj1
# print("删除完成")

# from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QPushButton
# #案例二
#
# app = QApplication(sys.argv)
# win1 = QWidget()     # 创建了一个窗口对象
# win1.setStyleSheet("background-color: blue;")
# win1.setWindowTitle("blue")
# win1.resize(500, 500)
# win1.show()
#
# time.sleep(2)
#
# win2 = QWidget(win1)
# win2.setStyleSheet("background-color: red;")
# win2.setWindowTitle("red")
# win2.resize(100, 100)
# # win2.setParent(win1)  # win1 为父对象，win2 = QWidget(win1) 效果一样
# win2.show()
#
# time.sleep(2)
#
# # 下面创建一些窗口中的小东西
# l1 = QLabel()
# b1 = QPushButton()
# l1.setParent(win1)
# b1.setParent(win1)
#
# l1.setText("label")
# b1.setText("button")
# l1.move(200, 200)
# b1.move(300, 200)
# l2 = QLabel()
# l2.setParent(win1)
# l2.setText("Label")
# l2.move(100, 200)
#
# # 遍历设置样式
# for i in win1.findChildren(QLabel):
#     i.setStyleSheet("color: green")
#
# l1.show()
# time.sleep(2)
#
# b1.show()
# time.sleep(2)
# l2.show()
#
# sys.exit(app.exec_())
#endregion


#region  1.4 信号操作   这是Qt中的核心机制， 主要用于 对象之间的通讯
# from PyQt5.Qt import *
# from PyQt5.QtCore import QObject
# from PyQt5.QtWidgets import QWidget, QPushButton, QApplication
#

#
#
# def destroy():
#     print("对象被摧毁")
#
# obj1 = QObject()
# obj2 = QObject()
# obj1.setParent(obj2)
# # obj.destroyed
# obj1.destroyed.connect(lambda: destroy())
#
# # 接下来  我们尝试触发一系列 的信号 ， 通过触发某些条件
#
#
# #  触发 改变对象名称的事件
# obj1.objectNameChanged.connect(lambda name:print("对象名称改变："+ name))
# obj1.setObjectName("xxx")
#
# # 断开槽与信号的连接
# obj1.blockSignals(True)  # 临时阻断连接
# obj1.setObjectName("1")
# print("连接数量："+str(obj1.receivers(obj1.objectNameChanged)))
#
#
# obj1.blockSignals(False)   # 再次开启连接
# obj1.objectNameChanged.connect(lambda name: print("第二个连接："+name))
# print("连接数量：" + str(obj1.receivers(obj1.objectNameChanged)))  # 查看有多少个槽连接这个信号
# obj1.setObjectName("2")
# del obj2


# 案例 1.4.4
#
# class Window(QWidget):
#
#     def __init__(self):
#         super().__init__()
#         self.setWindowTitle("test")  # 设置标题
#         self.resize(300, 300)  # 设置窗口大小
#         self.move(200, 300)  # 移动窗口
#         self.setup_ui()  # 调用创建控件的方法
#
#         def ret():
#             print("标题变化了")
#             # self.windowTitleChanged.disconnect()  # 断开槽与信号的关系
#             self.blockSignals(True)  # 临时断开连接也行
#
#         self.windowTitleChanged.connect(ret)        # 这种操作类似于设置了一个监听事件
#
#     def setup_ui(self):  # 添加控件的操作
#         self.btn()  # 添加按钮
#
#     num = 1
#
#     def btn(self):
#         b = QPushButton(self)
#         b.setText("点击我")
#         def ret():
#             if self.num == 1:
#                 self.setWindowTitle("1111")
#             elif self.num ==2:
#                 self.setWindowTitle("2222")
#             elif self.num ==3:
#                 self.setWindowTitle("3333")
#             else:
#                 self.setWindowTitle("4444")
#             self.num += 1
#
#             if self.num == 4:
#                 self.num =1
#             print(self.num)
#             print("被点击了")
#
#         b.clicked.connect(ret)     # 这里算是一个绑定了点击事件
#
#
# if __name__ == '__main__':
#     # 可以通过导包来运行窗口
#     import sys
#
#     app = QApplication(sys.argv)
#     # 创建窗口
#     w = Window()
#     # 显示窗口
#     w.show()
#     sys.exit(app.exec_())

#endregion



#  1.5 类型判定
# region 类型判定
# region  类型判定

# from PyQt5.Qt import *
# import sys
# from PyQt5.QtWidgets import QApplication, QLabel, QWidget, QPushButton
# from PyQt5.QtCore import QObject

# app = QApplication(sys.argv)
# w = QApplication(sys.argv)
# obj = QObject(w)
# w1 = QObject(w)
#
# l = QLabel()       #  l = QLabel(w)  这种写法不被允许了
# # l.setParent()        参数不能为   w啊
# print(w.isWidgetType())     # 判断是否为继承控件类型
# print(obj.isWidgetType())     # 判断是否为继承控件类型
# print(l.isWidgetType())
# print(w.inherits("QWidget"))           # 该函数判别 调用对象是否  继承了指定类型
# print(obj.inherits("QLabel"))
# print(l.inherits("QLabel"))
# sys.exit(app.exec_())


#  下面是一个案例 ，通过控件的类型才操作控件的显示效果
# class Window(QWidget):
#
#     def __init__(self):
#         super().__init__()
#         self.setWindowTitle("test")  # 设置标题
#         self.resize(500, 500)  # 设置窗口大小
#         self.move(300, 300)  # 移动窗口
#         self.setup_ui()  # 调用创建控件的方法
#
#     def setup_ui(self):  # 添加控件的操作
#         l = QLabel(self)
#         l.setText("first")
#         l.move(100, 100)
#
#         l2 = QLabel(self)
#         l2.setText("second")
#         l2.move(200, 100)
#
#         btn = QPushButton(self)
#         btn.setText("点我")
#         btn.move(300, 100)
#
#         for i in self.findChildren(QWidget):
#             if i.inherits("QLabel"):  # 如果为 label 类型，修改样式
#                 i.setStyleSheet("color: red; font-size: 20px")
#             else:
#                 i.setStyleSheet("color: blue; font-size: 20px")
#
# if __name__ == '__main__':
#     # 可以通过导包来运行窗口
#     import sys
#
#     app = QApplication(sys.argv)
#     # 创建窗口
#     w = Window()
#     # 显示窗口
#     w.show()
#     sys.exit(app.exec_())

#endregion
# </editor-fold>
# endregion





#region  1.6对象删除     1.7 事件处理
# from PyQt5.Qt import *
# import sys
# from PyQt5.QtWidgets import QApplication, QLabel, QWidget, QPushButton
# from PyQt5.QtCore import QObject, QEvent


# app = QApplication(sys.argv)
# w = QWidget()
# obj1 = QObject()
# obj2 = QObject()
# obj3 = QObject()
# obj3.setParent(obj2)
# obj2.setParent(obj1)
# obj1.destroyed.connect(lambda: print("obj1被释放"))
# obj2.destroyed.connect(lambda: print("obj2被释放"))
# obj3.destroyed.connect(lambda: print("obj3被释放"))
# # obj1.deleteLater()
# obj2.deleteLater()  # 等下一个循环开始时才会真正释放
# # del obj2 # 直接删除，但是这是把变量和对象的关联替换了，使得系统无法访问对象，不是真的删除
# print(obj1)
# w.show()
# sys.exit(app.exec_())


#  下面部分是  事件处理的一个案例
# class App(QApplication):
#      #     这第一个函数的意思大概是 监听到了 事件的发生， 然后 去启动对应的事件
#     def notify(self, rev, evt):
#         if rev.inherits("QPushButton") and evt.type() == QEvent.MouseButtonPress:
#             print("底层运行原理")
#             print(rev, evt)
#         return super().notify(rev, evt)      # 分发事件
#
#
# class Btn(QPushButton):
#
#     def event(self, evt):
#         if evt.type() == QEvent.MouseButtonPress:        # 事件过滤，  这里应该是在检测 鼠标按下事件
#             print("鼠标点击了", evt)
#         return super().event(evt)
#
#     def mousePressEvent(self, evt):
#         print("鼠标被点击。。。。。。")   #
#         return super().mousePressEvent(evt)
#
#
# app = App(sys.argv)
# w = QWidget()
# btn = Btn(w)
# btn.setText("按钮")
# btn.move(100, 100)
# btn.pressed.connect(lambda : print("按钮被按下"))
# btn.clicked.connect(lambda : print("按钮被点击"))
# btn.released.connect(lambda : print("按钮被松开"))
# w.show()
# sys.exit(app.exec_())



# endregion



#region   定时器操作
#
# from PyQt5.Qt import *
# import sys
# from PyQt5.QtCore import QObject
# from PyQt5.QtWidgets import QWidget, QApplication, QLabel
#

# class MyObject(QObject):
#
#     def timerEvent(self, evt):
#         #  这里是重载了原来的timerEvent方法
#         print(evt, "1")   # 每秒 打印一个
#         return super().timerEvent(evt)     # 这里的意思是加入自己的部分， 同时也调用父类方法
#
#
# app = QApplication(sys.argv)
# w = QWidget()
# w.setWindowTitle("定时器")
# w.resize(500, 500)
# obj = MyObject()
# t_id = obj.startTimer(500)     # 每秒执行一次，  通过继承来启动计时器
# # obj.killTimer(t_id)      # 这里是关闭定时器
# w.show()
# sys.exit(app.exec_())

#  这里验证之后 发现定时器  就是一个指定时间 就执行以此某些时间的方法


# 应用场景

# class MyLabel(QLabel):
#     def __init__(self, sec, *args, **kwargs):  # 使用不定长参数传参
#         super().__init__(*args, **kwargs)
#         self.move(20, 20)
#         self.setText(sec)
#         self.setStyleSheet("font-size: 20px; color: red;")
#         self.t_id = self.startTimer(1000)  # 1秒执行一次，通过继承的方法来启动计时器
#
#
#     def timerEvent(self, evt):
#             # 倒计时原理
#         sec = int(self.text())
#         sec -= 1
#         self.setText(str(sec))
#         if (sec == 0):
#             self.killTimer(self.t_id)  # 关闭定时器
#
#
# class MyQWidget(QWidget):
#     def __init__(self, *args, **kwargs):
#         super(MyQWidget, self).__init__(*args, **kwargs)
#         self.setWindowTitle("定时器")
#         self.resize(500, 500)
#         self.startTimer(1000)  # 动画
#
#     def timerEvent(self, evt):
#         current_w, current_h = self.width(), self.height()
#         if current_w > 1000 and current_h > 1000:
#             current_w -= 20
#             current_h -= 20
#         elif current_h < 1000 and current_w < 1000:
#             current_w += 20
#             current_h += 20
#         self.resize(current_w, current_h)
#
# app = QApplication(sys.argv)
# w = MyQWidget()
# MyLabel("10",w)    # 设置 10 秒为倒计时
# w.show()
# sys.exit(app.exec_())

#endregion


#  这里 是 鼠标的以及QWidget预言的一些实验
# from PyQt5.QtWidgets import QWidget, QApplication, QLabel
# import sys

# 语法部分的一些小测试
# print(QWidget.__base__)
# print(QWidget.mro())
# app = QApplication(sys.argv)
# w = QWidget()
# w.move(200, 200)
# w.resize(150, 150)
# print(w.x(), w.y())
# print(w.width(), w.height())
# w.show()


#  这里是 测试 检验 QWidget组件的大小位置属性
# app = QApplication(sys.argv)
# w = QWidget()
# w.move(100, 100)
# w.resize(200, 200)
# w.show()
# print(w.x())
# print(w.width())
# print(w.geometry())
# print(w.rect())
# print(w.frameSize())
# print(w.frameGeometry())
# print(w.pos())
# print(w.size())
#
# sys.exit(app.exec_())

# 桌面显示后获取的数据才准确，   或者说 才能获取数据

# app = QApplication(sys.argv)
# w = QWidget()
# w.resize(10, 10)
# w.setMinimumSize(50, 50)
# # w.setMaximumSize(250, 250)
#
# w.show()

# print(w.minimumSize())  # 得到最小尺寸
# print(w.maximumSize())  # 得到最大尺寸
# sys.exit(app.exec_())




# 下面是内容边距的内容  这一部分的操作有些像css了


# app = QApplication(sys.argv)
# w = QWidget()
# w.resize(500, 500)
#
# l = QLabel(w)
# l.setText("Hello World")
# l.setStyleSheet("background-color: red; font-size: 20px; font-weight: 500;")
# l.resize(300, 300)
# l.setContentsMargins(500, 500, 500, 0)  # 设置内容外边距
# print(l.contentsRect().getRect())  # 得到内容区域
# print(l.getContentsMargins())  # 得到内容外边距
#
# w.show()
# sys.exit(app.exec_())


#  鼠标相关    设置鼠标的样式

# app = QApplication(sys.argv)
# w = QWidget()
# w.resize(500, 500)
#
# pixmap = QPixmap(r"imgs\123.png") # 传入图片设置鼠标
# pixmap_new = pixmap.scaled(50, 50)  # 输入缩放的尺寸
# cursor = QCursor(pixmap_new)    # 实例化鼠标对象
# # w.setCursor(Qt.SizeAllCursor)      # 这是鼠标形状 ， 参数为鼠标的样式
# w.setCursor(cursor)   # 也可以传入一个鼠标对象， 后面的数字的意思是以左上角为标准
# # w.unsetCursor()   # 取消鼠标 的形状
# w.show()
# sys.exit(app.exec_())



# 重置 鼠标的形状
# app = QApplication(sys.argv)
# w = QWidget()
# w.resize(500, 500)
# current_cursor = w.cursor()  # 获取鼠标对象
# print(current_cursor.pos())  # 获得鼠标相对于电脑屏幕的位置坐标
# current_cursor.setPos(2000, 2000)  # 设置鼠标的位置
# w.show()
# sys.exit(app.exec_())



# 鼠标跟踪  所谓的鼠标跟踪， 其实就是 设置鼠标移动事件的条件
# 鼠标跟踪：
# 鼠标移动时，不处于按下状态，也会触发 mouseMoveEvent 事件
# 鼠标不跟踪：
#
# 鼠标移动时，必须处于按下状态，才会触发 mouseMoveEvent 事件
#  左键， 右键，  滚轮 都可以

# class MyWidget(QWidget):
#     def mouseMoveEvent(self, me):
#         print("鼠标移动了", me.localPos())   # 这里重载的是鼠标移动事件
#         #  这里 localPos（）  或者pos（） 方法可以得到鼠标相对于控件的位置
#
# app =QApplication(sys.argv)
# w = MyWidget()
# w.setWindowTitle("鼠标事件")
# w.resize(500, 500)
#
# w.setMouseTracking(False)
# print(w.hasMouseTracking())
# w.show()
# sys.exit(app.exec_())


# 案例，  鼠标按下 移动标签

# class MyWidget(QWidget):
#     def __init__(self):      # , *args, **kwargs
#         super().__init__()     #*args, **kwargs
#         self.resize(500, 500)
#         self.setWindowTitle("鼠标事件案例")
#         self.label = QLabel(self)
#         self.setup_ui()
#         print("类的初始化被完成")
#
#
#     def mouseMoveEvent(self, me):
#         x, y = me.x(), me.y()
#         self.label.move(x, y)
#
#
#     def setup_ui(self):
#         self.label.resize(100, 100)
#         self.label.setText("按住我！")
#         self.label.setStyleSheet("background-color: green; font-weight: bold;")
#
# if __name__ == '__main__':
#     app = QApplication(sys.argv)
#     w = MyWidget()
#     w.show()
#     sys.exit(app.exec_())

#endregion

#region  事件 非常重要的概念， 无论是在前端，后端还是游戏中， 都很重要的概念， 相应某些而设计的专门事件
# # from PyQt5.Qt import
# from PyQt5.QtWidgets import QWidget, QApplication

# 为了熟悉， 敲一遍
# class MyWindow(QWidget):
#
#     def __init__(self):
#         super().__init__()
#         self.setWindowTitle("Test")
#         self.resize(500, 500)
#         self.move(100, 100)
#         print("初始化被执行")
#
#     def showEvent(self, ev):
#         print("窗口被展示出来了, 打印下参数",ev)
#         # print(str(ev))
#         # print(str(self))
#
#     def closeEvent(self, ev):
#         print("窗口关闭, 打印下参数",ev)
#         # print(str(ev))
#         # print(str(self))
#
#     def resizeEvent(self, ev):
#         print("控件大小改变",ev)
#         # print(str(ev))
#         # print(str(self))
#
#     def enterEvent(self, ev):
#         print("鼠标进入窗口",ev)
#         # print(str(ev))
#         # print(str(self))
#
#     def leaveEvent(self, ev):
#         print("鼠标离开窗口",ev)
#         # print(str(ev))
#         # print(str(self))
#
#     def mouseReleaseEvent(self, ev):
#         print("鼠标松开", ev)
#         # print(str(ev))
#         # print(str(self))
#
#     def mouseMoveEvent(self, ev):
#         print("鼠标在移动",ev)
#         # print(str(ev))
#         # print(str(self))
#
#     def keyReleaseEvent(self, ev):
#         print("键盘松开了",ev)
#         # print(str(ev))
#         # print(str(self))
#
#     def focusInEvent(self, ev):
#         print("获得焦点", ev)
#         # print(str(ev))
#         # print(str(self))
#
#     def focusOutEvent(self, ev):
#         print("失去焦点", ev)
#         # print(str(ev))
#         # print(str(self))
#
#
#
# if __name__ == '__main__':
#     #     # 可以通过导包来运行窗口
#     #     import sys
#     app = QApplication(sys.argv)
#     # 创建窗口
#     w = MyWindow()
#     # 显示窗口
#     w.show()
#     sys.exit(app.exec_())



#endregion





#region 事件传递的概念      如果一个控件没有处理事件，  那么自动传递给父控件处理
#  有一个所谓事件对象的概念，   代表要处理的事件（可能）   有两种特殊方法， 自己处理事件， 或者自己忽略这个事件，然后往上层传递

# class Window(QWidget):
#     def mousePressEvent(self, ev):
#         print("顶层鼠标按下")
#
# class MidWindow(QWidget):
#     def mousePressEvent(self, ev):
#         ev.ignore()   # 转发给父对象，  但是也会接收对象
#         print(ev.isAccepted())
#         print("中间鼠标按下")
#
# class Label(QLabel):
#     def mousePressEvent(self, ev):
#         print("标签控件鼠标按下")
#         ev.accept()  # 不用转发给父对象，接收对象
#         print(ev.isAccepted())
#
# import PyQt5.Qt
# app = QApplication(sys.argv)
# w = Window()
# w.setWindowTitle("事件转发Test")
# w.resize(500, 500)
# m_w = MidWindow(w)
# m_w.resize(300, 300)
# # m_w.setAttribute(Qt.)    #Qt.WA_StyleBackground
# m_w.setStyleSheet("background-color: yellow;")
#
# label = Label(m_w)
# label.setText("这是一个标签")
# label.setStyleSheet("background-color: skyblue;")
# label.move(110, 110)
#
# w.show()
# sys.exit(app.exec_())


#创建一个窗口包含一个标签
# 鼠标进入标签时，展示欢迎光临
# 鼠标离开标签时，展示谢谢惠顾

# class Label(QLabel):
#     def __init__(self, *args, **kwargs):
#         super().__init__(*args, **kwargs)
#         self.resize(200, 200)
#         self.move(100, 100)
#         self.setStyleSheet("background-color: skyblue;")
#
#     def enterEvent(self, ev):
#         self.setText("欢迎光临")
#
#     def leaveEvent(self, ev):
#         self.setText("谢谢惠顾")
#
# app = QApplication(sys.argv)
# w = QWidget()
# w.setWindowTitle("鼠标事件案例")
# w.resize(500, 500)
# laber = Label(w)
# w.show()
# sys.exit(app.exec_())








#endregion


#region  案例二   监听用户按键

# class Label(QLabel):
#
#     def __init__(self, *args, **kwargs):
#         super().__init__(*args, **kwargs)
#         self.resize(200, 200)
#         self.move(100, 100)
#         self.setStyleSheet("background-color: skyblue; font-weight: 500;")
#         self.grabKeyboard()  # 捕获键盘事件
#         #self.releaseKeyborad()   # 停止捕获键盘事件
#
#
#     def keyPressEvent(self, ev):
#         # 监听 Tab键
#         if ev.key() == Qt.Key_Tab:    # 监听普通键
#             self.setText("用户点击的是Tab键")
#         #监听 Ctrl + C  修饰键Ctrl  并且普通键 C   Alt组合键
#         if ev.modifiers() == Qt.ControlModifier and ev.key() == Qt.Key_C:
#             self.setText("正在复制文本内容")
#
#         #  监听 Ctrl + Shift + v 修饰键 Ctrl + Shift （使用按位或组合获取） 并且普通键 V
#         if ev.modifiers() == Qt.ControlModifier | Qt.ShiftModifier and ev.key() == Qt.Key_V:
#             self.setText("正在粘贴内容")
#
# app = QApplication(sys.argv)
# w = QWidget()
# w.setWindowTitle("鼠标操作案例1")
# w.resize(500, 500)
# label = Label(w)
# w.show()
# sys.exit(app.exec_())


#endregion



#region  案例三 监听 鼠标 ，并根据鼠标设置事件
# class Window(QWidget):
#
#     def __init__(self):
#         super().__init__()
#         self.move_flag = False  # 判断是否在移动
#         print(self.move_flag)
#         self.setWindowTitle("内容拖动")  # 设置标题
#         self.resize(500, 500)  # 设置窗口大小
#         self.move(100, 100)  # 移动窗口
#         self.mouse = ()  # 移动前的坐标
#         self.origin = ()  # 原始的坐标
#         print(self.mouse, self.origin)
#
#
#     def mousePressEvent(self, evt):
#         """
#         print(evt.localPos())  # 得到是相对于窗口左上角的坐标
#         print(evt.globalPos())  # 得到的是相对于电脑左上角的坐标
#         """
#         if evt.button() == Qt.RightButton:    #  Qt.LeftButton |
#             self.move_flag = True  # 设定标记
#             self.mouse = (evt.globalX(), evt.globalY())
#             self.origin = (self.x(), self.y())  # 左上角坐标
#             print(self.mouse, self.origin)
#
#     def mouseMoveEvent(self, evt):
#         if self.move_flag:
#             # 相对移动
#             move_x = evt.globalX() - self.mouse[0]
#             move_y = evt.globalY() - self.mouse[1]
#             self.move(self.origin[0] + move_x, self.origin[1] + move_y)
#
#     def mouseReleaseEvent(self, evt):
#         # 确定最终位置
#         self.move_flag = False
#
#
# if __name__ == '__main__':
#     # 可以通过导包来运行窗口
#     import sys
#
#     app = QApplication(sys.argv)
#     # 创建窗口
#     w = Window()
#     # 显示窗口
#     w.show()
#     sys.exit(app.exec_())
#endregion


#region 2.9 父子关系

# app = QApplication(sys.argv)
# w = QWidget()
# w.setWindowTitle("父子关系")
# w.resize(500, 500)
#
# l1 = QLabel(w)
# # l1 = QLabel("标签1")     # 这里写成字符串难道也可以吗
# l1.setText("标签1")
#
# l2 = QLabel(w)
# l2.setText("标签2")
# l2.move(50, 0)
#
# l3 = QLabel(w)
# l3.setText("标签3")
# l3.move(100, 0)
#
# print(w.childAt(300, 0))  # 获得对应坐标的子控件
# print(l1, l2, l3)
# print(l2.parentWidget())   # 获得父控件
# print(w.childrenRect())
# print(w.children())
# print(w.childrenRect().getRect())    # 打印子控件所占有的举行区域
#
# w.show()
# sys.exit(app.exec_())

# endregion


# 创建若干个Label控件 ， 实现点击功能

# class MyWidget(QWidget):
#     def mousePressEvent(self, ev):
#         print(ev)
#         print(self.cursor())
#         specialObj = self.childAt(ev.x(), ev.y())     # 从这里我们可以知道 事件对象 也是可以由 x  y 坐标属性的
#         if specialObj:    # 如果点击了标签； 避免了报错
#             for i in self.findChildren(QLabel):
#                 # 清空别的控件的样式， 只留下自己选定的个那个
#                 i.setStyleSheet("")
#             specialObj.setStyleSheet("background-color: red;")    # 修改指定控件样式

# app = QApplication(sys.argv)      # 会弹出来的那窗口
# w= MyWidget()
# w.setWindowTitle("父子关系")
# w.resize(500, 500)
# for i in range(11):
#     l = QLabel(w)
#     l.setText(f"标签{i}")
#     l.move(50*i, 50*i)
#
# w.show()
# sys.exit(app.exec_())


#region  层级控制  顶层窗口  基本语法部分
# 高层级控件会被 底层级控件覆盖
# 有一些  可以主动 降层或者升层的 函数

# app = QApplication(sys.argv)
# w = QWidget()
# icon = QIcon(r"imgs\123.png")     # 创建 图标对象
# w.setWindowIcon(icon)     # 设置窗口图标
# print(icon)
# print(w.windowIcon())     # 获取图标对象
# w.setWindowTitle("Hello")        #  设置窗口标题， 默认为python
# print(w.windowTitle())      # 获取窗口标题
# w.setWindowOpacity(0.5)    # 设置窗口的不透明度
# w.setWindowState(Qt.WindowFullScreen)     # 此处为设置窗口的状态， 有 无状态， 最小化， 最大化， 全屏， 活动窗口等
# print(w.windowState())      # 获取窗口状态
# w.show()
# sys.exit(app.exec_())



#  最大化 最小化
# app = QApplication(sys.argv)
# w = QWidget()
# # w.showMaximized()    # 最大化展示
# # w.showMinimized()    # 最小化展示
# # w.showNormal()       # 正常展示
# # w.showFullScreen()   # 全屏展示
# print(w.isMinimized())   #  查看是否为最小化，  下面几个同理
# print(w.isMaximized())
# print(w.isFullScreen())
# w.show()
# sys.exit(app.exec_())



# 窗口标志
# app = QApplication(sys.argv)
# w = QWidget()
# w.setWindowFlags(Qt.WindowMaximizeButtonHint | Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint )    # 设置顶层窗口的 外观标志      设置窗口样式（主要是窗口边框、标题栏和窗口本身的样式）
# # 比如 默认情况下 运行弹出的窗口 有 叉叉键 可以退出 ，  有 方框 可以全屏，  有减号 可以隐藏， 这些都是样式
# w.show()
# sys.exit(app.exec_())      关于窗口样式 有很多 属性可以自己选择


#endregion

#region 小练手
# 创建一个窗口，要求：
#
# 无边框，无标题栏
# 窗口半透明
# 自定义最大化，最小化，关闭按钮
# 支持拖拽用户区移动

#  自己小小的尝试了一下， 发现不行 啊   ，不是自定义的
# class MyWindow(QWidget):
#     def __init__(self):
#         super().__init__()
#         self.resize(500, 500)
#         self.move(600, 300)
#         self.setWindowOpacity(0.5)
#
# app = QApplication(sys.argv)
# w = MyWindow()
# # 来到设置窗口样式的部分
# w.setWindowFlags(Qt.WindowMinMaxButtonsHint | Qt.ToolTip | Qt.WindowCloseButtonHint)
#
# w.show()
# sys.exit(app.exec_())



# class Window(QWidget):
#
#     def __init__(self, *args, **kwargs):
#         super().__init__(*args, **kwargs)
#         self.setWindowTitle("案例")
#         self.move_flag = False   # 默认没有移动
#         self.resize(500, 500)
#         self.move(300, 300)
#         self.setWindowOpacity(0.7)
#         self.setup_ui()   # 调用创建控件的方法
#         self.origin=()    # 初始坐标，相对于窗口的
#         self.mouse = ()    # 鼠标按下时，  鼠标相对于 窗口的坐标
#
#
#
#     def setup_ui(self):  # 这里是对控件的操作
#         def close_w():
#             self.deleteLater()   # 删除主窗口
#
#         btn_close = QPushButton(self)
#         btn_close.clicked.connect(close_w)     # 设置了一个点击的监听事件
#         btn_close.setText("X")
#         btn_close.move(self.width() - 25, 8)
#         #  这里为什么 修改了 控件 按钮的位置
#
#         def max_or_min(btn):
#             if self.isMaximized():
#                 self.showNormal()
#                 btn.setText("+")
#             else:
#                 self.showMaximized()    # 这里的逻辑好像 不是最大就是最小显示模式啊
#                 btn.setText("-")
#             count = 1
#             self.findChild(QLabel).resize(self.width(), 45)
#             for i in self.findChildren(QPushButton):
#                 i.move(self.width() - count * 25, 8)   # 动态化设置按钮的位置
#                 count += 1
#
#         btn_maxOrMin = QPushButton(self)
#         btn_maxOrMin.move(self.width() - 50, 8)
#         btn_maxOrMin.clicked.connect(lambda :max_or_min(btn_maxOrMin))
#         btn_maxOrMin.setText("+")
#         # qApp.setStyleSheet("""QPushButton{
#         #     font-size: 20px;
#         #     color: black;
#         #     font-weight: 800;
#         #     border: 2px solid black;
#         #     margin: 5px;
#         # }""")  # 设置样式
#         # 设置窗口头部框架
#         label = QLabel(self)
#         label.resize(self.width(), 45)
#         label.setStyleSheet("background-color: skyblue;")
#         label.lower()
#
#     def mousePressEvent(self, evt):  # 设置窗口移动
#         if evt.button() == Qt.LeftButton:
#             self.move_flag = True         # 这个标志决定着是否允许窗口的移动
#             self.mouse = (evt.globalX(), evt.globalY())
#             self.origin = (self.x(), self.y())
#             # 这里我有一个疑问了，  就是 鼠标坐标 和 控件坐标 和  事件坐标 之间的关系
#             # print("主窗口坐标", self.x(), self.y())
#             # print("事件中的坐标", evt.x(), evt.y()) # 经过验证得到 事件的坐标即为鼠标位置坐标
#             # print("实践中全局坐标", evt.globalX(), evt.globalY())
#
#
#     def mouseMoveEvent(self, evt):
#         self.move(evt.globalX() - self.mouse[0] + self.origin[0],
#                   evt.globalY() - self.mouse[1] + self.origin[1]) if self.move_flag else None
#
#     def mouseReleaseEvent(self, *args, **kwargs):
#         self.move_flag = False
#
#
#
# if __name__ =='__main__':
#     app = QApplication(sys.argv)
#     app.setStyleSheet("""QPushButton{
#         font-size: 20px;
#         color: black;
#         font-weight: 800;
#         border: 2px solid black;
#         margin: 5px;
#     }""")  # 设置样式
#
#
#     # 创建窗口，  无边框， 无标题栏
#     w = Window(flags=Qt.FramelessWindowHint)
#     w.show()
#     sys.exit(app.exec_())
#endregion


#region  交互状态

#  第一部分 ：  是否启用功能

# app = QApplication(sys.argv)
# w = QWidget()
# btn = QPushButton(w)
# btn.setText("点击")
# print(btn.isEnabled())  # 判断按钮是否可用
# btn.pressed.connect(lambda : btn.setEnabled(False))   # 点击后按钮禁用
# w.show()
# sys.exit(app.exec_())



# 第二部分：  显示和隐藏
# app = QApplication(sys.argv)
# w = QWidget()
# w.resize(500, 500)
# btn = QPushButton(w)
# print(btn.isVisible())    # 判断控件是否可见
# btn.clicked.connect(lambda :btn.hide())    # 降按钮隐藏
# print(btn.isHidden())   # 判断窗口是否隐藏
# w.setVisible(True)      # 使窗口可见， 先绘制父窗口
# #  w.setHidden(False)   效果一样
# sys.exit(app.exec_())


# 是否可编辑
# setWindowModified(bool)  # 设置是否被编辑
# isWindowModified()  # 窗口是否被编辑

# app = QApplication(sys.argv)
# w = QWidget()
# w.setWindowTitle("[*]交互状态")
# w.setWindowModified(True)   # 可编辑状态会显示 [ ]里面的* 好， 即有* 号 就处于被编辑状态
# print(w.isWindowModified())     # 判断窗口是否处于可编辑状态
# # w.setVisible(True)   # 和show作用类似
# w.show()    # 换为 show 依旧有效
# sys.exit(app.exec_())

# 实操了之后  实际  意义与应用 仍然有些不清楚



#   判断是否为活跃窗口
# app = QApplication(sys.argv)
# w1 = QWidget()
# w2 = QWidget()
# w2.show()
# w1.show()
# w1.clicked.connect(lambda: print(w2.isActiveWindow(),w1.isActiveWindow() ))
# w2.clicked.connect(lambda: print(w2.isActiveWindow(),w1.isActiveWindow() ))
#
# print(w2.isActiveWindow())   # 展示是否处于活跃窗口
# print(w1.isActiveWindow())
# sys.exit(app.exec_())



# 控件关闭
# app = QApplication(sys.argv)
# w1 = QWidget()
# w2 = QWidget()
# w1.destroyed.connect(lambda: print("w1销毁"))
# w2.destroyed.connect(lambda: print("w2销毁"))
#
# w2.show()
# w1.show()
# w1.setAttribute(Qt.WA_DeleteOnClose, True)  # 如果加了这行代码，窗口/控件就会在关闭的同时删除，效果和deleteLater类似
# w1.close()  # 效果和setVisible（False）类似       也就是 show（）的反面
# w2.setVisible(False)  # 使得窗口不可见，但是窗口并没有删除
# w2.deleteLater()  # 销毁窗口/控件
# sys.exit(app.exec_())

#endregion


# 几个很实用的小功能练手

#region  第一个
# import hashlib
#
# class Window(QWidget):
#
#     def __init__(self):
#         super().__init__()
#         self.setWindowTitle("案例[8]")   # 设置标题
#         self.resize(500, 500)   # 设置窗口的大小
#         self.move(100, 100)
#         self.setup_ui()     # 使用该方法创建控件
#
#
#     def setup_ui(self):
#         #  这里先省略一步创建样式
#         text = QLineEdit(self)      # pyqt5 中的 文本控制组件
#         text.resize(300, 40)
#         text.move(100, 20)
#
#         def change_():     #  特别i注意 ， 这里面的  变量 可以使用 setup_ui  方法内部全部的
#             self.setWindowModified(True)
#             btn.setEnabled(len(text.text()) > 0)    # 当文本框有内容时， 按钮可用
#
#         text.textChanged.connect(change_)   # 绑定事件，  这里 函数对象应该写于不写都可以吧
#         # 创建按钮
#         btn = QPushButton(self)
#         btn.resize(80, 40)
#         btn.setText("登录")
#         btn.move(210, 80)
#         btn.setEnabled(False)   # 按钮不可用
#
#
#         def click_():
#             label.setVisible(True)  # 显示标签
#             # 使用 hash 加密
#
#             salt = hashlib.md5("liu".encode("utf-8"))
#             salt.update(text.text().encode("utf-8"))
#             content = salt.hexdigest()
#             if content == 'a8b2a2561ec21479990c48706a743c9a':  # 条件判断
#                 label.setText("登录成功")
#             else:
#                 label.setText("登录失败")
#
#             text.setText("")
#             self.setWindowModified(False)
#
#
#         # 创建标签
#         label = QLabel(self)
#         label.resize(100, 40)
#         label.move(220, 120)
#         label.setVisible(True)
#         btn.clicked.connect(click_)    # 绑定事件




# if __name__ =='__main__':
#     app =QApplication(sys.argv)
#     w = Window()
#     w.show()
#     sys.exit(app.exec_())

#endregion


#region  第二个 消息提示   意思是当鼠标移到上面的时候 ，会出现提示信息
# app = QApplication(sys.argv)
# w = QMainWindow()  # 使用组合窗口
# w.resize(500, 500)
# w.statusBar()  # 创建状态栏，可以显示状态提示
# l = QLabel(w)
# l.setStatusTip("这是信息提示")   # 设置状态提示
# l.setText("你好")
# print(l.statusTip())  # 获取状态提示
# w.show()
# sys.exit(app.exec_())


#endregion

#region  第三个 工具提示  和消息提示类似， 不过可以设定事件限制
# app = QApplication(sys.argv)
# w = QWidget()
# w.resize(500, 500)
# l = QLabel(w)
# l.setToolTip("这是一个工具提示")
# l.setText("坤坤")
# l.setToolTipDuration(1000)  # 工具提示展示时间为 1 秒
# print(l.toolTip())  # 获取工具提示
# w.show()
# sys.exit(app.exec_())

#endregion

#region  第四个 意思提示  需要切换到某个模式，才能查看提示
# app = QApplication(sys.argv)
# w = QWidget(flags=Qt.WindowContextHelpButtonHint)    # 意思是有一个帮助和关闭， 但是关闭不可用
# w.resize(500, 500)
# l = QLabel(w)
# l.setWhatsThis("这是啥，这是一个意思提示")  # 设置一个意思提示
# l.setText("坤坤")
# print(l.whatsThis())  # 获取意思提示
# w.show()
# sys.exit(app.exec_())


#第五个  焦点控制  单个控件
"""
setFocus()  # 指定控件获取焦点
setFocusPolicy(mode)  # 设置焦点获取策略
    - 参数
        Qt.TabFocus    通过 Tab 获取焦点
        Qt.ClickFocus  通过点击获取焦点
        Qt.StrongFocus 通过以上两种方式获取焦点
        Qt.NoFocus     不能通过以上两种方式获取焦点
clearFocus()  # 取消焦点
"""

# app = QApplication(sys.argv)
# # 创建三个文本框
# w = QWidget()
# w.resize(500, 500)
# t1 = QLineEdit(w)
# t1.setFocusPolicy(Qt.NoFocus)
# t2 = QLineEdit(w)
# t2.move(50, 50)
# t2.setFocus()  # 设置焦点
# t2.setFocusPolicy(Qt.TabFocus)  # 获取焦点的方式
# t2.clearFocus()  # 取消焦点
# t3 = QLineEdit(w)
# t3.move(100, 100)
# w.show()
# sys.exit(app.exec_())


"""
focusWidget()  # 获取子控件中当前焦距的控件
focusNextChild()  # 聚焦下一个子控件
focusPreviousChild()  # 聚焦上一个子控件
focusNextPrevChild()  # true：下一个 false：上一个
setTabOrder(pre_widget, next_widget)  # 静态方法，用于设置子控件获取焦点的先后顺序
"""

# app = QApplication(sys.argv)
# w = QWidget()
# w.resize(500, 500)
# t1 = QLineEdit(w)
# t1.setFocus()  # 给 t1 设置焦点
# t2 = QLineEdit(w)
# t2.move(50, 50)
# t3 = QLineEdit(w)
# t3.move(100, 100)
# w.show()
# # QWidget.setTabOrder(t3, t2)  # 按 tab 获取焦点的顺序 t3 > t2 > t1
# w.focusNextChild()  # 聚焦下一个子控件
# w.focusNextPrevChild(True)  # 结果是t3有焦点
# print(w.focusWidget())  # 获取子控件中当前焦距的控件
# sys.exit(app.exec_())





